Hands-on_Ex03

Author

Andre Ong Jia Kang

Published

April 26, 2024

Modified

May 1, 2025

3. Programming Interactive Data Visualisation with R

Launching R packages

Code
pacman::p_load(ggrepel, patchwork, 
               ggthemes, hrbrthemes,
               tidyverse, ggiraph, plotly, 
               patchwork, DT) 

Importing the data

Code
exam_data <- read_csv("data/Exam_data.csv")

3.4 Interactive Data Visualisation - ggiraph methods

3.4.1 Tooltip effect with tooltip aesthetic

Code
p <- ggplot(data=exam_data, aes(x = MATHS)) +
  geom_dotplot_interactive(aes(tooltip = ID),
    stackgroups = TRUE,  binwidth = 1, method = "histodot") +
  scale_y_continuous(NULL, breaks = NULL)
girafe(
  ggobj = p, width_svg = 6,height_svg = 6*0.618
)

3.5 Interactivity

3.5.1 Displaying multiple information on tooltip

Code
exam_data$tooltip <- c(paste0( "Name = ", exam_data$ID,"\n Class = ", exam_data$CLASS)) 

p <- ggplot(data=exam_data, aes(x = MATHS)) +
  geom_dotplot_interactive(aes(tooltip = exam_data$tooltip), 
    stackgroups = TRUE, binwidth = 1, method = "histodot") +
  scale_y_continuous(NULL, breaks = NULL)
girafe(
  ggobj = p,width_svg = 8,height_svg = 8*0.618
)

3.6 Interactivity

3.6.1 Customising Tooltip style

Code
tooltip_css <- "background-color:white; #<<
font-style:bold; color:black;" #<<

p <- ggplot(data=exam_data, aes(x = MATHS)) +
  geom_dotplot_interactive( aes(tooltip = ID),  stackgroups = TRUE, binwidth = 1, method = "histodot") +               
  scale_y_continuous(NULL, breaks = NULL)

girafe( ggobj = p, width_svg = 6, height_svg = 6*0.618,
  options = list(    #<<
    opts_tooltip(    #<<
      css = tooltip_css)) #<<
)                                        

3.6.2 Displaying statistics on tooltip

Code
tooltip <- function(y, ymax, accuracy = .01) {
  mean <- scales::number(y, accuracy = accuracy)
  sem <- scales::number(ymax - y, accuracy = accuracy)
  paste("Mean maths scores:", mean, "+/-", sem)
}

gg_point <- ggplot(data=exam_data, 
                   aes(x = RACE),
) +
  stat_summary(aes(y = MATHS, tooltip = after_stat(tooltip(y, ymax))),  
    fun.data = "mean_se", geom = GeomInteractiveCol, fill = "light blue") +
  
  stat_summary(aes(y = MATHS), fun.data = mean_se, geom = "errorbar", width = 0.2, size = 0.2)

girafe(ggobj = gg_point, width_svg = 8, height_svg = 8*0.618)

3.6.3 Hover effect with data_id aesthetic

Code
p <- ggplot(data=exam_data, 
       aes(x = MATHS)) +
  geom_dotplot_interactive(  aes(data_id = CLASS),  stackgroups = TRUE, binwidth = 1, method = "histodot") +               
  scale_y_continuous(NULL, breaks = NULL)
girafe(                                  
  ggobj = p, width_svg = 6, height_svg = 6*0.618                      
)

3.6.4 Styling hover effect

Code
p <- ggplot(data=exam_data, aes(x = MATHS)) +
  geom_dotplot_interactive(aes(data_id = CLASS),stackgroups = TRUE,binwidth = 1, method = "histodot") +               
  scale_y_continuous(NULL, breaks = NULL)

girafe(ggobj = p, width_svg = 6, height_svg = 6*0.618, options = list(        opts_hover(css = "fill: #202020;"),  
    opts_hover_inv(css = "opacity:0.2;") 
  )                                        
)                                        

3.6.5 Combining tooltip and hover effect

Code
p <- ggplot(data=exam_data, aes(x = MATHS)) +
  geom_dotplot_interactive(  aes(data_id = CLASS),  stackgroups = TRUE, binwidth = 1, method = "histodot") +               
  scale_y_continuous(NULL, breaks = NULL)

girafe(                                  
  ggobj = p, width_svg = 6, height_svg = 6*0.618, options = list(                     
    opts_hover(css = "fill: #202020;"),  
    opts_hover_inv(css = "opacity:0.2;") 
  )                                        
)    

3.6.6 Click effect with onclick

Code
exam_data$onclick <- sprintf("window.open(\"%s%s\")",
"https://www.moe.gov.sg/schoolfinder?journey=Primary%20school",
as.character(exam_data$ID))

p <- ggplot(data=exam_data, aes(x = MATHS)) + geom_dotplot_interactive(              
    aes(onclick = onclick), stackgroups = TRUE, binwidth = 1,method = "histodot") + scale_y_continuous(NULL,               
                     breaks = NULL)
girafe(ggobj = p, width_svg = 6,height_svg = 6*0.618)

3.6.7 Coordinated Multiple Views with ggiraph

Code
p1 <- ggplot(data=exam_data, 
       aes(x = MATHS)) + geom_dotplot_interactive(aes(data_id = ID),              
    stackgroups = TRUE,binwidth = 1, method = "histodot") +  
  coord_cartesian(xlim=c(0,100)) + 
  scale_y_continuous(NULL,breaks = NULL)

p2 <- ggplot(data=exam_data, aes(x = ENGLISH)) +
  geom_dotplot_interactive(aes(data_id = ID),stackgroups = TRUE, binwidth = 1, method = "histodot") + 
  coord_cartesian(xlim=c(0,100)) + 
  scale_y_continuous(NULL, breaks = NULL)

girafe(code = print(p1 + p2), width_svg = 6, height_svg = 3,
       options = list( opts_hover(css = "fill: #202020;"),opts_hover_inv(css = "opacity:0.2;"))) 

3.7 Interactive Data Visualisation - plotly methods

3.7.1 Creating an interactive scatter plot: plot_ly() method

Code
plot_ly(data = exam_data,  x = ~MATHS, y = ~ENGLISH)

3.7.2 Working with visual variable: plot_ly() method

Code
plot_ly(data = exam_data, x = ~ENGLISH, y = ~MATHS, color = ~RACE)

3.7.3 Creating an interactive scatter plot: ggplotly() method

Code
p <- ggplot(data=exam_data, aes(x = MATHS, y = ENGLISH)) +
  geom_point(size=1) +
  coord_cartesian(xlim=c(0,100), ylim=c(0,100))
ggplotly(p)

3.7.4 Coordinated Multiple Views with plotly

Code
d <- highlight_key(exam_data)
p1 <- ggplot(data=d, aes(x = MATHS,y = ENGLISH)) +
  geom_point(size=1) +
  coord_cartesian(xlim=c(0,100), ylim=c(0,100))

p2 <- ggplot(data=d, aes(x = MATHS, y = SCIENCE)) +
  geom_point(size=1) +
  coord_cartesian(xlim=c(0,100), ylim=c(0,100))

subplot(ggplotly(p1),
        ggplotly(p2))

3.8 Interactive Data Visualisation - crosstalk methods

3.8.1 Interactive Data Table: DT package

Code
DT::datatable(exam_data, class= "compact")

3.8.2 Linked brushing: crosstalk method

Code
d <- highlight_key(exam_data) 
p <- ggplot(d, aes(ENGLISH, MATHS)) + 
  geom_point(size=1) +
  coord_cartesian(xlim=c(0,100), ylim=c(0,100))

gg <- highlight(ggplotly(p), "plotly_selected")  

crosstalk::bscols(gg, DT::datatable(d), widths = 5)   

(Extra): Scatterplots with marginal distribution

Creating the plot using patchwork.

Scatterplot + Density plot

Code
# Scatter plot
scatter_plot <- ggplot(data = exam_data, 
                       aes(x = MATHS, y = ENGLISH)) +
  geom_point(alpha = 0.8) +
  theme_minimal() +
  labs(title = "Scatter Plot with Marginal Density Plots",
       x = "Maths Score",
       y = "English Score")

# Marginal density plot for x-axis (MATHS)
density_x <- ggplot(data = exam_data, 
                    aes(x = MATHS)) +
  geom_density(fill = "gray", alpha = 0.6) +
  theme_minimal() +
  theme(axis.title.x = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank())

# Marginal density plot for y-axis (ENGLISH)
density_y <- ggplot(data = exam_data, 
                    aes(x = ENGLISH)) +
  geom_density(fill = "gray", alpha = 0.6) +
  coord_flip() +  # Flip to make it vertical
  theme_minimal() +
  theme(axis.title.y = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank())

# Combine plots using patchwork
combined_plot <- density_x + 
  plot_spacer() +  # Empty space
  scatter_plot + 
  density_y +
  plot_layout(ncol = 2, widths = c(4, 1), heights = c(1, 4))

# Display the combined plot
combined_plot

Creating the plot using ggExtra

pacman::p_load(ggExtra)

Scatterplot + Density plot

Code
# Step 1: Create scatter plot
scatter_plot <- ggplot(data = exam_data, 
                       aes(x = MATHS, y = ENGLISH)) +
  geom_point(alpha = 0.8) +
  theme_minimal() +
  labs(title = "Scatter Plot with Marginal Density Plots",
       x = "Maths Score",
       y = "English Score")

# Step 2: Add marginal density plots
ggMarginal(scatter_plot,
           type = "density",
           fill = "gray",
           alpha = 0.6,
           color = "black")

Scatterplot + Boxplot

Code
# Step 1: Create scatter plot
scatter_plot <- ggplot(data = exam_data, 
                       aes(x = MATHS, y = ENGLISH)) +
  geom_point(alpha = 0.8) +
  theme_minimal() +
  labs(title = "Scatter Plot with Marginal Boxplots",
       x = "Maths Score",
       y = "English Score")

# Step 2: Add marginal boxplots
ggMarginal(scatter_plot, 
           type ="boxplot", 
           color = "black")

Scatterplot + Histogram

Code
# Step 1: Create scatter plot
scatter_plot <- ggplot(data = exam_data, 
                       aes(x = MATHS, y = ENGLISH)) +
  geom_point(alpha = 0.8) +
  theme_minimal() +
  labs(title = "Scatter Plot with Marginal Histogram Plots",
       x = "Maths Score",
       y = "English Score")

# Step 2: Add marginal histogram plots
ggMarginal(scatter_plot, 
           type = "histogram",
           color = "black")

Interactive Scatterplot + Marginal Density Plots using patchwork

Code
# Scatter plot
scatter_plot <- ggplot(data = exam_data, 
                       aes(x = MATHS, 
                           y = ENGLISH,
                           text = paste("Student", ID,
                                        "<br>Maths: ", MATHS, 
                                        "<br>English: ", ENGLISH))) +
  geom_point(alpha = 0.8) +
  theme_minimal() +
  labs(title = "Scatter Plot with Marginal Density Plots",
       x = "Maths Score",
       y = "English Score")

# Marginal density plot for x-axis (MATHS)
density_x <- ggplot(data = exam_data, 
                    aes(x = MATHS)) +
  geom_density(fill = "gray", alpha = 0.6) +
  theme_minimal() +
  theme(axis.title.x = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank())

# Marginal density plot for y-axis (ENGLISH)
density_y <- ggplot(data = exam_data, 
                    aes(x = ENGLISH)) +
  geom_density(fill = "gray", alpha = 0.6) +
  coord_flip() +  # Flip to make it vertical
  theme_minimal() +
  theme(axis.title.y = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank())

interactive_scatter <- ggplotly(scatter_plot, tooltip = "text")

# Convert marginal plots to plotly
interactive_x_density <- ggplotly(density_x) %>% hide_legend() 
interactive_y_density <- ggplotly(density_y) %>% hide_legend()

# Step 3: Arrange all plots together using subplot
final_plot <- subplot(
  interactive_x_density, 
  plot_spacer(),
  interactive_scatter, 
  interactive_y_density,
  nrows = 2, heights = c(0.2, 0.8), widths = c(0.8, 0.2),
  shareX = TRUE, shareY = TRUE
)

final_plot

4. Programming Animated Statistical Graphics with R

Launching R packages

Code
pacman::p_load(readxl, gifski, gapminder,
               plotly, gganimate, tidyverse)

Importing Data

Code
# Step 1: 
col <- c("Country", "Continent")

#Step 2:
globalPop <- read_xls("data/GlobalPopulation.xls",
                      sheet="Data") %>%
  mutate(across(col, as.factor)) %>%
  mutate(Year = as.integer(Year))

4.3 Animated Data Visualisation: gganimate methods

4.3.1 Building a static population bubble plot

Code
ggplot(globalPop, aes(x = Old, y = Young, size = Population,colour = Country)) +
  geom_point(alpha = 0.7, show.legend = FALSE) +
  scale_colour_manual(values = country_colors) +
  scale_size(range = c(2, 12)) +
  labs(title = 'Year: {frame_time}', x = '% Aged', y = '% Young') 

4.3.2 Building the animated bubble plot

Code
ggplot(globalPop, aes(x = Old, y = Young, size = Population, colour = Country)) +
  geom_point(alpha = 0.7, show.legend = FALSE) +
  scale_colour_manual(values = country_colors) +
  scale_size(range = c(2, 12)) +
  labs(title = 'Year: {frame_time}', x = '% Aged', y = '% Young') +
  transition_time(Year) +       
  ease_aes('linear')          

4.4 Animated Data Visualisation: plotly

4.4.1 Building an animated bubble plot: ggplotly() method

Code
gg <- ggplot(globalPop, 
       aes(x = Old, 
           y = Young, 
           size = Population, 
           colour = Country)) +
  geom_point(aes(size = Population,
                 frame = Year),
             alpha = 0.7) +
  scale_colour_manual(values = country_colors) +
  scale_size(range = c(2, 12)) +
  labs(x = '% Aged', 
       y = '% Young') + 
  theme(legend.position='none')

ggplotly(gg)

4.4.2 Building an animated bubble plot: plot_ly() method

Code
bp <- globalPop %>%
  plot_ly(x = ~Old, 
          y = ~Young, 
          size = ~Population, 
          color = ~Continent,
          sizes = c(2, 100),
          frame = ~Year, 
          text = ~Country, 
          hoverinfo = "text",
          type = 'scatter',
          mode = 'markers'
          ) %>%
  layout(showlegend = FALSE)
bp